// src/filters/global-exception.filter.ts
import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  HttpStatus,
} from '@nestjs/common';
import { Request, Response } from 'express';
import { MongooseError } from 'mongoose';

@Catch()
export class GlobalExceptionFilter implements ExceptionFilter {
  catch(exception: any, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();

    // 默认错误结构
    let status = 'INTERNAL_ERROR';
    let code = HttpStatus.INTERNAL_SERVER_ERROR;
    let message = '服务器内部错误';

    // 处理 NestJS 内置 HTTP 异常
    if (exception.getStatus) {
      status = this.getErrorCode(code);
      code = exception.getStatus();
      message = exception.message || message;
    }

    // 处理类验证错误（class-validator）
    if (exception.getResponse?.().message) {
      const validationError = exception.getResponse();
      status = 'VALIDATION_FAILED';
      code = HttpStatus.BAD_REQUEST;
      message = validationError.message;
    }

    // 处理 JWT 相关错误
    if (
      exception.name === 'JsonWebTokenError' ||
      exception.name === 'UnauthorizedException'
    ) {
      status = 'INVALID_TOKEN';
      code = HttpStatus.UNAUTHORIZED;
      message = '登录凭证无效';
    }

    // 处理数据库查询错误
    // 处理 MongoDB 唯一索引冲突
    if (
      exception instanceof MongooseError &&
      exception.name === 'MongoServerError'
    ) {
      const mongoError = exception as any;

      if (mongoError.code === 11000) {
        status = 'DUPLICATE_KEY';
        code = HttpStatus.CONFLICT;
        message = this.formatDuplicateKeyError(mongoError);
      }
    }

    console.log('exception.name', exception.name, exception);
    // 处理文档验证错误
    if (exception.name === 'ValidationError') {
      status = 'DOCUMENT_VALIDATION_FAILED';
      code = HttpStatus.BAD_REQUEST;
      message = Object.values(exception.errors)
        .map((err: any) => err.message)
        .join('; ');
    }

    // id不存在
    if (exception.name === 'CastError') {
      status = 'NOT_FOUND';
      code = HttpStatus.BAD_REQUEST;
      message = `id: ${exception.value} 不存在`;
    }

    // 生产环境隐藏敏感信息
    const isProduction = process.env.NODE_ENV === 'production';
    const errorResponse = {
      code,
      message,
      //   timestamp: new Date().toISOString(),
      //   path: request.url,
      ...(!isProduction && { stack: exception.stack }),
    };

    response.status(code).json(errorResponse);
  }

  private getErrorCode(code: number): string {
    const codes = {
      400: 'BAD_REQUEST',
      401: 'UNAUTHORIZED',
      403: 'FORBIDDEN',
      404: 'NOT_FOUND',
      500: 'INTERNAL_ERROR',
    };
    return codes[code] || 'UNKNOWN_ERROR';
  }

  private formatDuplicateKeyError(err: any): string {
    const key = Object.keys(err.keyPattern)[0];
    const value = err.keyValue[key];
    return `${key} '${value}' 已存在`;
  }
}
